<template>
	<view class="waterfall-flow1-container" :style="{height: contentHeight}">
		<view 
			class="waterfall-flow1-item" 
			:style="[{
				'--offset': offset + 'px',
				top: itemStyle[index].top || 0, 
				left: itemStyle[index].left || 0, 
				visibility: itemStyle[index].visibility || 'hidden'
			}, boxStyle]"
			:id="'waterfallitem-'+ item[idKey]"
			v-for="(item, index) in showList" :key="index"
			@click="$emit('clickItem', {item, index})"
		>
			<image 
				class="waterfall-flow1-img" 
				mode="widthFix" 
				:class="{ single }"
				:style="imageStyle"
				:src="item[imageSrcKey] || ''"
				@load="imageRender(item, index)" 
				@error="imageRender(item, index)" 
				@click="$emit('clickImage', {item, index})"
			/>
			<!--  #ifdef  MP-WEIXIN -->
			<slot name="slot{{index}}" />
			<!--  #endif -->
			<!--  #ifndef  MP-WEIXIN -->
			<slot :name="'slot'+ index" />
			<!--  #endif -->
		</view>
	</view>
</template>

<script>
export default {
	name: 'waterfall-flow1',
	props: {
		list: {
			type: Array, // 要渲染的数据列表
			default: []
		},
		offset: {
			type: Number, // offset 间距，单位为 px
			default: 10
		},
		idKey: {
			type: String, // 列表渲染的 key 的键名，值必须唯一，默认为 id
			default: 'id'
		},
		imageSrcKey: {
			type: String, // 图片的key，要显示在src上的
			default: 'image'
		},
		imageStyle: {
			type: Object, // 图片的style样式
			default: {}
		},
		boxStyle: {
			type: Object, // 每一项的style样式
			default: {}
		},
		single: {
			type: Boolean, // 是否是单独的渲染图片的样子，只控制图片圆角而已
			default: false
		}
	},
	data() {
		return {
			showList: [], // 页面的渲染的数据
			current: 0, // 当前渲染到第几个数据了
			itemStyle: [], // 列的每项样式
			colHeight: [], // 保存了两列的高
		}
	},
	computed: {
		contentHeight() {
			if (this.colHeight.length) {
				const maxHeight = Math.max.apply(null, this.colHeight);
				const height = maxHeight - this.offset;
				return height + 'px';
			} else {
				return 'auto';
			}
		}
	},
	watch: {
		list(val) {
			// 数据追加，如果只是改变数据重新渲染，length长度一样，那么在这之前应该先调clear方法
			if (val.length > this.showList.length) {
				this.pushQueue();
			}
		}
	},
	methods: {
		// 执行队列，每次都只加载一条数据到showList中
		pushQueue() {
			if (this.showList.length >= this.list.length) {
				this.$emit('load', {
					total: this.current,
					colHeight: this.colHeight
				})
				return;
			};
			this.$set(this.showList, this.current, this.list[this.current]);
			this.$set(this.itemStyle, this.current, {});
			this.current++;
		},
		// 图片渲染时触发，用于获取高度，动态算出每个元素该出现的位置
		imageRender(item, index) {
			setTimeout(() => {
				const idName = `#waterfallitem-${item[this.idKey]}`;
				const query = uni.createSelectorQuery().in(this);
				query.select(idName).fields({ size: true }, data => {
					const colHeight = this.colHeight;
					if (colHeight.length < 2) { // 小于两个数据
						let top = 0; // 首两个元素的top都是0
						let left = 0; // 元素的位置，左边那一排始终都是0，我们只用判断右边就好
						if (colHeight.length == 1) { // 已经有一个长度了，说明现在是第二个元素
							left = data.width + this.offset;
						}
						this.itemStyle.splice(index, 1, {
							left: left +'px',
							top: top +'px',
							visibility: 'initial' // 这个主要是用于页面刚渲染时top，left都在左上角，还没被赋值时位置变化造成的闪烁
						});
						const height = data.height + this.offset;
						this.colHeight.push(height);
					} else {
						const minHeight = Math.min.apply(null, colHeight); // 得到最矮的列
						const minIndex = colHeight.indexOf(minHeight); // 最矮的列的下标，用于追加数据
						let top = minHeight; // 旧的高度
						let left = 0; // 元素的位置，左边那一排始终都是0，我们只用判断右边就好
						if (minIndex == 1) { // 数组0，左边，1右边
							left = data.width + this.offset;
						}
						this.itemStyle.splice(index, 1, {
							left: left +'px',
							top: top +'px',
							visibility: 'initial'
						});
						const newHeight = minHeight + this.offset + data.height; // 旧的列的高度+间距+当前item的高
						this.colHeight.splice(minIndex, 1, newHeight); // 更新最矮的列的总高度
					}
					this.pushQueue(); // 执行下一个队列
				}).exec();
			}, 300);
		},
		// 清除数据，用于重新渲染
		clear() {
			this.showList = [];
			this.current = 0;
			this.itemStyle = [];
			this.colHeight = [];
		},
		// 额外导出的方法，用于更新数据或强制重新渲染
		update() {
			this.clear();
			this.$nextTick(() => {
				this.pushQueue();
			})
		}
	}
}
</script>

<style scoped>
.waterfall-flow1-container {
	position: relative;
	width: 100%;
	overflow: hidden;
}
.waterfall-flow1-item {
	width: calc((100% - var(--offset) * (2 - 1)) / 2); /* 自动计算每项所占空间 */
	position: absolute;
	visibility: hidden; /* 解决渲染时每张图都显示在第一个位置 */
}
.waterfall-flow1-img {
	width: 100%;
	height: auto;
	will-change: transform;
	display: block;
}
.single {
	border-radius: 8rpx;
}
</style>